package io.gitee.guoguoleo.wrapper;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.util.NumberUtil;
import io.gitee.guoguoleo.enums.SqlLike;
import io.gitee.guoguoleo.model.WhereFieldInfo;
import io.gitee.guoguoleo.utils.FieldUtil;
import io.gitee.guoguoleo.utils.SqlUtil;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.OrderByElement;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class QueryWrapper<T>  {

    private final Wrapper<T> wrapper;

    public QueryWrapper() {
        this.wrapper = new Wrapper<>();

        this.wrapper.andFlag = true;
        this.wrapper.orFlag = false;

        this.wrapper.whereExpressionList = new CopyOnWriteArrayList<>();
        this.wrapper.orderByElementList = new CopyOnWriteArrayList<>();
        this.wrapper.selectColumnList = new CopyOnWriteArrayList<>();
        this.wrapper.excludeSelectColumnList = new CopyOnWriteArrayList<>();
    }

    public List<WhereFieldInfo> getWhere(){
        return this.wrapper.whereExpressionList;
    }

    public List<OrderByElement> getOrderBy(){
        return this.wrapper.orderByElementList;
    }

    public List<String> getSelect(){
        return this.wrapper.selectColumnList;
    }


    public List<String> getExclude(){
        return this.wrapper.excludeSelectColumnList;
    }

    /**
     * and操作，不声明默认先使用
     *
     * @return this
     */
    public QueryWrapper<T> and() {
        this.wrapper.and();
        return this;
    }

    /**
     * or操作，需要声明后使用
     *
     * @return this
     */
    public QueryWrapper<T> or() {
        this.wrapper.and();
        return this;
    }

    /**
     * eq
     *
     * @param condition 前置条件
     * @param fieldName 字段名称
     * @param value     值
     * @return this
     */
    public QueryWrapper<T> eq(boolean condition, String fieldName, Object value) {
        this.wrapper.eq(condition, fieldName, value);
        return this;
    }

    /**
     * eq
     *
     * @param fieldName 字段名称
     * @param value     值
     * @return this
     */
    public QueryWrapper<T> eq(String fieldName, Object value) {
        return this.eq(true, fieldName, value);
    }


    /**
     * eq
     *
     * @param condition 前置条件
     * @param func1     字段名称
     * @param value     值
     * @return this
     */
    public QueryWrapper<T> eq(boolean condition, Func1<T, ?> func1, Object value) {
        String fieldName = LambdaUtil.getFieldName(func1);
        return this.eq(condition, fieldName, value);
    }

    /**
     * eq
     *
     * @param func1 字段名称
     * @param value 值
     * @return this
     */
    public QueryWrapper<T> eq(Func1<T, ?> func1, Object value) {
        String fieldName = LambdaUtil.getFieldName(func1);
        return this.eq(true, fieldName, value);
    }

    /**
     * in
     *
     * @param condition 前置条件
     * @param fieldName 名称
     * @param valueList 值列表
     * @return this
     */
    public QueryWrapper<T> in(boolean condition, String fieldName, Collection<? extends Serializable> valueList) {
        this.wrapper.in(condition, fieldName, valueList);
        return this;
    }

    /**
     * in
     *
     * @param fieldName 名称
     * @return this
     */
    public QueryWrapper<T> in(String fieldName, Collection<? extends Serializable> valueList) {
        return this.in(true, fieldName, valueList);
    }

    /**
     * in
     *
     * @param condition 前置条件
     * @param fieldName 名称
     * @param values    值列表
     * @return this
     */
    public QueryWrapper<T> in(boolean condition, String fieldName, Serializable... values) {
        List<Serializable> valueList = ListUtil.toList(values);
        return this.in(condition, fieldName, valueList);
    }

    /**
     * in
     *
     * @param fieldName 名称，支持驼峰或者下划线
     * @return this
     */
    public QueryWrapper<T> in(String fieldName, Serializable... values) {
        return this.in(true, fieldName, values);
    }


    /**
     * in
     *
     * @param condition 前置条件
     * @param func1     字段
     * @param valueList 值列表
     * @return this
     */
    public QueryWrapper<T> in(boolean condition, Func1<T, ?> func1, Collection<? extends Serializable> valueList) {
        String fieldName = LambdaUtil.getFieldName(func1);
        return this.in(condition, fieldName, valueList);
    }

    /**
     * in
     *
     * @param func1     字段
     * @param valueList 值列表
     * @return this
     */
    public QueryWrapper<T> in(Func1<T, ?> func1, Collection<? extends Serializable> valueList) {
        String fieldName = LambdaUtil.getFieldName(func1);
        return this.in(true, fieldName, valueList);
    }

    /**
     * in
     *
     * @param condition 前置条件
     * @param func1     字段
     * @param values    值列表
     * @return this
     */
    public QueryWrapper<T> in(boolean condition, Func1<T, ?> func1, Serializable... values) {
        String fieldName = LambdaUtil.getFieldName(func1);
        List<Serializable> valueList = ListUtil.toList(values);
        return this.in(condition, fieldName, valueList);
    }

    /**
     * in
     *
     * @param func1  字段
     * @param values 值列表
     * @return this
     */
    public QueryWrapper<T> in(Func1<T, ?> func1, Serializable... values) {
        String fieldName = LambdaUtil.getFieldName(func1);
        List<Serializable> valueList = ListUtil.toList(values);
        return this.in(true, fieldName, valueList);
    }


    /**
     * like
     *
     * @param condition 前置条件
     * @param fieldName 字段名称
     * @param value     值
     * @param sqlLike   like类型
     * @return this
     */
    public QueryWrapper<T> like(boolean condition, String fieldName, Object value, SqlLike sqlLike) {
        this.wrapper.like(condition, fieldName, value, sqlLike);
        return this;
    }

    /**
     * like
     *
     * @param condition 前置条件
     * @param fieldName 字段名称
     * @param value     值
     * @return this
     */
    public QueryWrapper<T> like(boolean condition, String fieldName, Object value) {
        return this.like(condition, fieldName, value, SqlLike.DEFAULT);
    }

    /**
     * like
     *
     * @param fieldName 字段名称
     * @param value     值
     * @return this
     */
    public QueryWrapper<T> like(String fieldName, Object value) {
        return this.like(true, fieldName, value, SqlLike.DEFAULT);
    }


    /**
     * like
     *
     * @param condition 前置条件
     * @param func1     字段名称
     * @param value     值
     * @param sqlLike   like类型
     * @return this
     */
    public QueryWrapper<T> like(boolean condition, Func1<T, ?> func1, Object value, SqlLike sqlLike) {
        String fieldName = LambdaUtil.getFieldName(func1);
        return this.like(condition, fieldName, value, sqlLike);
    }

    /**
     * like
     *
     * @param condition 前置条件
     * @param func1     字段名称
     * @param value     值
     * @return this
     */
    public QueryWrapper<T> like(boolean condition, Func1<T, ?> func1, Object value) {
        String fieldName = LambdaUtil.getFieldName(func1);
        return this.like(condition, fieldName, value, SqlLike.DEFAULT);
    }

    /**
     * like
     *
     * @param func1 字段名称
     * @param value 值
     * @return this
     */
    public QueryWrapper<T> like(Func1<T, ?> func1, Object value) {
        String fieldName = LambdaUtil.getFieldName(func1);
        return this.like(true, fieldName, value, SqlLike.DEFAULT);
    }


    /**
     * asc排序
     *
     * @param condition     前置条件
     * @param fieldNameList 字段列表
     * @return this
     */
    public QueryWrapper<T> orderByAsc(boolean condition, Collection<String> fieldNameList) {
        this.wrapper.orderByAsc(condition, fieldNameList);
        return this;
    }

    /**
     * asc排序
     *
     * @param fieldNameList 字段列表
     * @return this
     */
    public QueryWrapper<T> orderByAsc(Collection<String> fieldNameList) {
        return this.orderByAsc(true, fieldNameList);
    }

    /**
     * asc排序
     *
     * @param condition  前置条件
     * @param fieldNames 字段列表
     * @return this
     */
    public QueryWrapper<T> orderByAsc(boolean condition, String... fieldNames) {
        List<String> fieldNameList = ListUtil.toList(fieldNames);
        return this.orderByAsc(condition, fieldNameList);
    }

    /**
     * asc排序
     *
     * @param fieldNames 字段列表
     * @return this
     */
    public QueryWrapper<T> orderByAsc(String... fieldNames) {
        List<String> fieldNameList = ListUtil.toList(fieldNames);
        return this.orderByAsc(true, fieldNameList);
    }

    /**
     * asc排序
     *
     * @param condition 前置条件
     * @param func1s    字段列表
     * @return this
     */
    @SafeVarargs
    public final QueryWrapper<T> orderByAsc(boolean condition, Func1<T, ?>... func1s) {
        List<String> fieldNameList = ListUtil.toList(func1s).stream()
                .map(LambdaUtil::getFieldName)
                .toList();
        return this.orderByAsc(condition, fieldNameList);
    }

    /**
     * asc排序
     *
     * @param func1s 字段列表
     * @return this
     */
    @SafeVarargs
    public final QueryWrapper<T> orderByAsc(Func1<T, ?>... func1s) {
        return this.orderByAsc(true, func1s);
    }

    /**
     * desc排序
     *
     * @param condition     前置条件
     * @param fieldNameList 字段列表
     * @return this
     */
    public QueryWrapper<T> orderByDesc(boolean condition, Collection<String> fieldNameList) {
        this.wrapper.orderByDesc(condition, fieldNameList);
        return this;
    }

    /**
     * desc排序
     *
     * @param fieldNameList 字段列表
     * @return this
     */
    public QueryWrapper<T> orderByDesc(Collection<String> fieldNameList) {
        return this.orderByDesc(true, fieldNameList);
    }

    /**
     * desc排序
     *
     * @param condition  前置条件
     * @param fieldNames 字段列表
     * @return this
     */
    public QueryWrapper<T> orderByDesc(boolean condition, String... fieldNames) {
        List<String> fieldNameList = ListUtil.toList(fieldNames);
        return this.orderByDesc(condition, fieldNameList);
    }

    /**
     * desc排序
     *
     * @param fieldNames 字段列表
     * @return this
     */
    public QueryWrapper<T> orderByDesc(String... fieldNames) {
        List<String> fieldNameList = ListUtil.toList(fieldNames);
        return this.orderByDesc(true, fieldNameList);
    }

    /**
     * desc排序
     *
     * @param condition 前置条件
     * @param func1s    字段列表
     * @return this
     */
    @SafeVarargs
    public final QueryWrapper<T> orderByDesc(boolean condition, Func1<T, ?>... func1s) {
        List<String> fieldNameList = ListUtil.toList(func1s).stream()
                .map(LambdaUtil::getFieldName)
                .toList();
        return this.orderByDesc(condition, fieldNameList);
    }

    /**
     * desc排序
     *
     * @param func1s 字段列表
     * @return this
     */
    @SafeVarargs
    public final QueryWrapper<T> orderByDesc(Func1<T, ?>... func1s) {
        return this.orderByDesc(true, func1s);
    }



    /**
     * 当前字段查询
     */
    public QueryWrapper<T> select(List<String> fieldNameList){
        if (CollUtil.isEmpty(fieldNameList)) {
            throw new RuntimeException("至少要有一个查询字段");
        }
        for (String fieldName : fieldNameList) {
            this.wrapper.selectColumnList.add(FieldUtil.toField(fieldName));
        }
        return this;
    }

    /**
     * 当前字段查询
     */
    public QueryWrapper<T> select(String...fieldNames){
        List<String> fieldNameList = ListUtil.toList(fieldNames);
        return this.select(fieldNameList);
    }

    /**
     * 当前字段查询
     */
    @SafeVarargs
    public final QueryWrapper<T> select(Func1<T, ?>... func1s){
        List<String> func1List = ListUtil.toList(func1s).stream()
                .map(LambdaUtil::getFieldName)
                .toList();
        return this.select(func1List);
    }


    /**
     * 当前字段查询
     */
    public QueryWrapper<T> exclude(List<String> fieldNameList){
        for (String fieldName : fieldNameList) {
            this.wrapper.excludeSelectColumnList.add(FieldUtil.toField(fieldName));
        }
        return this;
    }

    /**
     * 当前字段查询
     */
    public QueryWrapper<T> exclude(String...fieldNames){
        List<String> fieldNameList = ListUtil.toList(fieldNames);
        return this.exclude(fieldNameList);
    }

    /**
     * 当前字段查询
     */
    @SafeVarargs
    public final QueryWrapper<T> exclude(Func1<T, ?>... func1s){
        List<String> func1List = ListUtil.toList(func1s).stream()
                .map(LambdaUtil::getFieldName)
                .toList();
        return this.exclude(func1List);
    }
}
